package com.dragon.modules.yuegou.client.wechat_mini.conn;

import com.dragon.modules.yuegou.web.Check;
import org.apache.http.HttpEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;

import java.io.File;
import java.io.OutputStream;
import java.lang.reflect.Type;

/**
 * 微信客户端
 * 
 * @author liuwu
 * @date 2019年7月5日
 *
 */
public interface IMiniClient {

	/**
	 * 使用GET方法进行接口调用
	 * 
	 * @param path 接口路径（不含base_url）
	 * @return 请求构造器
	 */
	Builder get(String path);

	/**
	 * 使用POST方法进行接口调用
	 * 
	 * @param path 接口路径（不含base_url）
	 * @return 请求构造器
	 */
	Builder post(String path);

	/**
	 * 请求构造器
	 * 
	 * @author liuwu
	 * @date 2019年7月5日
	 *
	 */
	interface Builder {

		/**
		 * 使用GET方法
		 * 
		 * @param path 接口路径
		 * @return this
		 */
		Builder get(String path);

		/**
		 * 使用POST方法
		 * 
		 * @param path 接口路径
		 * @return this
		 */
		Builder post(String path);

		/**
		 * 设置JSON（RequestBody）
		 * 
		 * @param body RequestBody
		 * @return this
		 */
		Builder json(Object body);

		/**
		 * 设置请求文件<br>
		 * 使用表单格式提交文件
		 * 
		 * @param file 文件
		 * @return this
		 */
		default Builder media(File file) {
			Check.notNull(file, "media file is required");
			HttpEntity httpEntity = MultipartEntityBuilder.create().setMode(HttpMultipartMode.RFC6532)
					.addBinaryBody("media", file, ContentType.DEFAULT_BINARY, file.getName()).build();
			return httpEntity(httpEntity);
		}

		/**
		 * 设置HttpEntity
		 * 
		 * @param httpEntity Apache请求实体
		 * @return this
		 */
		Builder httpEntity(HttpEntity httpEntity);

		/**
		 * 设置请求参数
		 * 
		 * @param name  参数名称
		 * @param value 参数值
		 * @return this
		 */
		Builder parameter(String name, String value);

		/**
		 * 设置接口调用凭证
		 * 
		 * @param accessToken 接口调用凭证
		 * @return this
		 */
		default Builder accessToken(String accessToken) {
			return parameter("access_token", accessToken);
		}

		/**
		 * 执行请求并把响应字节写入输出流<br>
		 * 
		 * @param output 输出流
		 */
		void execute(OutputStream output);

		/**
		 * 执行请求并
		 * 
		 * @param resultType 响应类型
		 * @return 响应对象，经过JSON反序列化的响应对象
		 */
		<T> T execute(Type resultType);
	}

}
